package com.zts.base.page.interceptor;

import com.github.miemiedev.mybatis.paginator.domain.Order;
import com.github.miemiedev.mybatis.paginator.domain.PageBounds;
import com.github.miemiedev.mybatis.paginator.domain.Paginator;
import com.zts.base.page.PagedList;
import com.zts.base.page.PageBound;
import com.zts.base.page.PageOrder;
import com.zts.base.page.PageOrderDirection;
import org.apache.ibatis.session.RowBounds;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by Zhangkh on 2017/6/1.
 */
@Aspect
@Component
public class PageableTranslator {

    private Logger logger = LoggerFactory.getLogger(PageableTranslator.class);

    private Order.Direction translate(PageOrderDirection direction) {
        Order.Direction result = null;

        if (direction == PageOrderDirection.ASC) {
            result = Order.Direction.ASC;
        } else if (direction == PageOrderDirection.DESC) {
            result = Order.Direction.DESC;
        }

        return result;
    }

    private Order translate(PageOrder pageOrder) {
        return pageOrder == null ? null :
                new Order(pageOrder.getProperty(), translate(pageOrder.getDirection()), pageOrder.getExpr());
    }

    private List<Order> translateOrders(List<PageOrder> pageOrders) {
        return pageOrders == null ? null :
                pageOrders.stream().filter(o -> o != null).map(this::translate).collect(Collectors.toList());
    }

    private PageBounds translate(PageBound pageBound) {
        if (pageBound == null) {
            return null;
        }

        PageBounds pageBounds =
                new OffsetPageBounds(pageBound.isContainsTotal(), pageBound.getOffset(), pageBound.getLimit(), translateOrders(pageBound.getOrders()));
        pageBounds.setAsyncTotalCount(pageBound.isAsyncTotal());

        return pageBounds;
    }

    @SuppressWarnings("unchecked")
    private PagedList translate(com.github.miemiedev.mybatis.paginator.domain.PageList pageList) {
        if (pageList == null) {
            return null;
        }

        PagedList result = new PagedList();

        result.addAll(pageList);
        Paginator paginator = pageList.getPaginator();
        if (paginator != null) {
            result.setTotal((long) paginator.getTotalCount());
            result.setLimit((long) paginator.getLimit());
            result.setOffset((long) paginator.getOffset());
        }

        return result;
    }

    @Around(value = "execution(* com.zts.*.*.mapper.*.*(..)) && args(..,rowBounds)", argNames = "rowBounds")
    public Object translate(ProceedingJoinPoint pjp, RowBounds rowBounds) throws Throwable {
        Object[] args = pjp.getArgs();

        if (rowBounds instanceof PageBound) {
            args[args.length-1] = translate((PageBound) rowBounds);
        }

        Object result = pjp.proceed(args);

        if (result instanceof com.github.miemiedev.mybatis.paginator.domain.PageList) {
            return translate((com.github.miemiedev.mybatis.paginator.domain.PageList)result);
        } else {
            return result;
        }
    }
}